// directory.cc 
//	Routines to manage a directory of file names.
//
//	The directory is a table of fixed length entries; each
//	entry represents a single file, and contains the file name,
//	and the location of the file header on disk.  The fixed size
//	of each directory entry means that we have the restriction
//	of a fixed maximum size for file names.
//
//	The constructor initializes an empty directory of a certain size;
//	we use ReadFrom/WriteBack to fetch the contents of the directory
//	from disk, and to write back any modifications back to disk.
//
//	Also, this implementation has the restriction that the size
//	of the directory cannot expand.  In other words, once all the
//	entries in the directory are used, no more files can be created.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "utility.h"
#include "filehdr.h"
#include "directory.h"
#include "debug.h"
#include "synchdisk.h"
#include <string>

// Sectors containing the file headers for the bitmap of free sectors,
// and the directory of files.  These file headers are placed in well-known
// sectors, so that they can be located on boot-up.
#define FreeMapSector 		0
#define DirectorySector 	1

// Initial file sizes for the bitmap and directory; until the file system
// supports extensible files, the directory size sets the maximum number
// of files that can be loaded onto the disk.
#define FreeMapFileSize 	(NumSectors / BitsInByte)
#define NumDirEntries 		10
#define DirectoryFileSize 	(sizeof(DirectoryEntry) * NumDirEntries + 2*sizeof(int))
//----------------------------------------------------------------------
// Directory::Directory
// 	Initialize a directory; initially, the directory is completely
//	empty.  If the disk is being formatted, an empty directory
//	is all we need, but otherwise, we need to call FetchFrom in order
//	to initialize it from disk.
//
//	"size" is the number of entries in the directory
//----------------------------------------------------------------------

Directory::Directory(int size) {
	parentSector = selfSector = DirectorySector;
	table = new DirectoryEntry[size];
	tableSize = size;
	for (int i = 0; i < tableSize; i++)
		table[i].inUse = FALSE;
}
Directory::Directory(int size, int self, int parent) {
	table = new DirectoryEntry[size];
	tableSize = size;
	for (int i = 0; i < tableSize; i++)
		table[i].inUse = FALSE;
	parentSector = parent;
	selfSector = self;
}
//----------------------------------------------------------------------
// Directory::~Directory
// 	De-allocate directory data structure.
//----------------------------------------------------------------------

Directory::~Directory() {
	delete[] table;
}

//----------------------------------------------------------------------
// Directory::FetchFrom
// 	Read the contents of the directory from disk.
//
//	"file" -- file containing the directory contents
//----------------------------------------------------------------------

void Directory::FetchFrom(OpenFile *file) {
	int size = tableSize * sizeof(DirectoryEntry);
	(void) file->ReadAt((char *) table, size, 0);
	(void) file->ReadAt((char *) &parentSector, sizeof(int), size);
	(void) file->ReadAt((char *) &selfSector, sizeof(int), size+sizeof(int));
}

//----------------------------------------------------------------------
// Directory::WriteBack
// 	Write any modifications to the directory back to disk
//
//	"file" -- file to contain the new directory contents
//----------------------------------------------------------------------

void Directory::WriteBack(OpenFile *file) {
	int size = tableSize * sizeof(DirectoryEntry);
	(void) file->WriteAt((char *) table, size, 0);
	(void) file->WriteAt((char *) &parentSector, sizeof(int), size);
	(void) file->WriteAt((char *) &selfSector, sizeof(int), size+sizeof(int));
}

int Directory::FindDirIndex(char *name) {
	return FindIndex(name, true);
}

int Directory::FindFileIndex(char *name) {
	return FindIndex(name, false);
}

//----------------------------------------------------------------------
// Directory::FindIndex
// 	Look up file name in directory, and return its location in the table of
//	directory entries.  Return -1 if the name isn't in the directory.
//
//	"name" -- the file name to look up
//----------------------------------------------------------------------

int Directory::FindIndex(char *name, bool isDir) {//edit
	for (int i = 0; i < tableSize; i++) {
//		char* temp = new char[128];
//		kernel->synchDisk->ReadSector(table[i].namesector, temp);
		if (table[i].inUse && isDir == table[i].isDir && !strncmp(table[i].name, name,
				FileNameMaxLen)) {
//			delete[] temp;
			return i;
		}
//		delete[] temp;
	}
	return -1; // name not in directory
}

int Directory::FindFile(char *name) // Find the sector number of the
{
	return Find(name, false);
}
int Directory::FindDir(char *name) // Find the sector number of the
{
	Directory * dir = new Directory(DirectoryFileSize);
	OpenFile * df;
	string dirname = string(name);
	string tmp = "";
	int b=0, e=dirname.find_first_of('/');
	if(e == -1){
		delete dir;
		return Find(name, true);
	}
	else if(e >= 0){
		if(e == 0)
			b = 1;
		e = dirname.find_first_of('/', b);
		if(e == -1){
			delete dir;
			return Find((name+1), true);
		}
		tmp = dirname.substr(b, e-b);
		int nd_1 = FindDir((char*)tmp.c_str());
		df = new OpenFile(nd_1);
		dir->FetchFrom(df);
		delete df;
		return dir->FindDir((char *)(dirname.substr(e, dirname.length()-e)).c_str());
	}
}

//----------------------------------------------------------------------
// Directory::Find
// 	Look up file name in directory, and return the disk sector number
//	where the file's header is stored. Return -1 if the name isn't 
//	in the directory.
//
//	"name" -- the file name to look up
//----------------------------------------------------------------------

int Directory::Find(char *name, bool isDir) {
	int i = FindIndex(name, isDir);

	if (i != -1)
		return table[i].sector;
	return -1;
}

//Add file or directory
bool Directory::AddFile(char *name, int newSector, PersistentBitmap *freeMap) {
	return Add(name, newSector, freeMap, false, 0);
}
bool Directory::AddDir(char *name, int newSector, PersistentBitmap *freeMap, int psector) {
	return Add(name, newSector, freeMap, true, psector);
}
//----------------------------------------------------------------------
// Directory::Add
// 	Add a file into the directory.  Return TRUE if successful;
//	return FALSE if the file name is already in the directory, or if
//	the directory is completely full, and has no more space for
//	additional file names.
//
//	"name" -- the name of the file being added
//	"newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------

bool Directory::Add(char *name, int newSector, PersistentBitmap *freeMap,
		bool isDir, int psector) {
	if (FindIndex(name, isDir) != -1)
		return FALSE;
	//edit
	for (int i = 0; i < tableSize; i++)
		if (!table[i].inUse) {
			table[i].inUse = TRUE;
//			table[i].namesector = freeMap->FindAndSet();
//			ASSERT(table[i].namesector >= 0);
//			char* temp = new char[128];
			strncpy(table[i].name, name, FileNameMaxLen);
//			kernel->synchDisk->WriteSector(table[i].namesector, temp);
			table[i].sector = newSector;
			table[i].isDir = isDir;
			//edit
			if (isDir) {
//				OpenFile *dirf = new OpenFile(newSector);
//				Directory *newdir = new Directory(DirectoryFileSize, newSector, psector);
//				newdir->WriteBack(dirf);
			} else {
				FileHeader *hdr = new FileHeader;
				hdr->FetchFrom(newSector);
				hdr->SetFileType(name);
				hdr->WriteBack(newSector);
				delete hdr;

			}
//			delete[] temp;
			return TRUE;
		}
	return FALSE; // no space.  Fix when we have extensible files.
}

//----------------------------------------------------------------------
// Directory::Remove
// 	Remove a file name from the directory.  Return TRUE if successful;
//	return FALSE if the file isn't in the directory. 
//
//	"name" -- the file name to be removed
//----------------------------------------------------------------------

bool Directory::Remove(char *name, PersistentBitmap *freeMap, bool isDir) {
	int i = FindIndex(name, isDir);

	if (i == -1)
		return FALSE; // name not in directory
	table[i].inUse = FALSE;
	//edit
//	ASSERT(freeMap->Test(table[i].namesector));
//	freeMap->Clear(table[i].namesector);
	return TRUE;
}


bool Directory::RemoveFile(char *name, PersistentBitmap *freeMap) // Remove a file from the directory    //edit
{
	return Remove(name, freeMap, false);
}
bool Directory::RemoveDir(char *name, PersistentBitmap *freeMap) // Remove a file from the directory    //edit
{
	return Remove(name, freeMap, true);
}

bool Directory::isEmpty()
{
	for(int i=0; i<tableSize; i++){
		if(table[i].inUse)
			return false;
	}
	return true;
}

//----------------------------------------------------------------------
// Directory::List
// 	List all the file names in the directory. 
//----------------------------------------------------------------------

void Directory::List() {//edit
	for (int i = 0; i < tableSize; i++)
		if (table[i].inUse) {
			printf("%-25s", table[i].name);
			if(table[i].isDir)
				printf("Directory\n");
			else
				printf("File\n");
		}
}

//----------------------------------------------------------------------
// Directory::Print
// 	List all the file names in the directory, their FileHeader locations,
//	and the contents of each file.  For debugging.
//----------------------------------------------------------------------

void Directory::Print() {
	FileHeader *hdr = new FileHeader;

	printf("Directory contents:\n");
	for (int i = 0; i < tableSize; i++)
		if (table[i].inUse) {
			printf("Name: %s, Sector: %d, ", table[i].name, table[i].sector);
			if(table[i].isDir)
				printf("   Directory\n");
			else
				printf("   File\n");
			hdr->FetchFrom(table[i].sector);
			hdr->Print();
		}
	printf("\n");
	delete hdr;
}
void Directory::PrintSectors()
{
	FileHeader *hdr = new FileHeader;
	printf("\nDirectory Sectors Used:\n");
	cout<<"File Header Sector: "<<this->selfSector<<" "<<endl;
	hdr->FetchFrom(this->selfSector);
	hdr->PrintSectors();

}
//Rename a File
void Directory::Rename(char *sour, char* dest)
{
	int index = 0;
	index = FindFileIndex(sour);
	strcpy(table[index].name,dest);
}
